home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / dev / src / adoc_src.lha / adoc-0.17 / strexpand.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-20  |  7.2 KB  |  358 lines

  1. /*                                                               -*- C -*-
  2.  *  STREXPAND.C
  3.  *
  4.  *  (c)Copyright 1990 by Tobias Ferber,  All Rights Reserved
  5.  *
  6.  *  This file is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published
  8.  *  by the Free Software Foundation; either version 1 of the License,
  9.  *  or (at your option) any later version.
  10.  *
  11.  *  This file is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to
  18.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* $VER: $Id: strexpand.c,v 1.7 1995/03/20 18:14:04 tf Exp $ */
  22.  
  23. #include <ctype.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <stdarg.h>
  27.  
  28. typedef struct rule {
  29.   struct rule *rules[256];
  30.   char *rhs;
  31. } rule_t;
  32.  
  33. /*
  34.  *  Dieses Array enth"alt an der Position rules[x].rhs den String in den `x'
  35.  *  "ubersetzt werden soll und/oder einen Zeiger rules[x].rules auf die Liste,
  36.  *  die in (rules[x].rules)[y] die "Ubersetzungen f"ur `xy' enthalten...
  37.  */
  38.  
  39. static rule_t *rules[256];
  40.  
  41. /*
  42. */
  43.  
  44. static rule_t *rule_new(void)
  45. {
  46.   rule_t *r= (rule_t *)malloc( sizeof(rule_t) );
  47.  
  48.   if(r)
  49.   {
  50.     int c;
  51.  
  52.     for(c=0; c<256; c++)
  53.       (r->rules)[c]= (rule_t *)0;
  54.  
  55.     r->rhs = (char *)0;
  56.   }
  57.  
  58.   return r;
  59. }
  60.  
  61. /*
  62. */
  63.  
  64. static rule_t *rule_dispose(rule_t *r)
  65. {
  66.   if(r)
  67.   {
  68.     int c;
  69.  
  70.     for(c=0; c<256; c++)
  71.       (r->rules)[c]= rule_dispose( r->rules[c] );
  72.  
  73.     r->rhs= (char *)0;
  74.  
  75.     free(r);
  76.   }
  77.  
  78.   return (rule_t *)0;
  79. }
  80.  
  81. /*
  82. */
  83.  
  84. static int rule_add(char *lhs, char *rhs)
  85. {
  86.   int err= 0;
  87.  
  88.   if(lhs && *lhs)
  89.   {
  90.     int c;
  91.     rule_t **R;
  92.  
  93.     for(R=&rules[0], c= (int)(unsigned char)*lhs; c && (err==0); c= (int)(unsigned char)*++lhs)
  94.     {
  95.       if( !R[c] )
  96.         R[c]= rule_new();
  97.  
  98.       if(R[c])
  99.       {
  100.         if(lhs[1])
  101.           R= R[c]->rules;
  102.  
  103.         else
  104.           R[c]->rhs= (rhs ? rhs : "");  /* Fri Feb 24 18:20:39 1995 */
  105.       }
  106.       else err= 2;
  107.     }
  108.   }
  109.   else err= 1;
  110.  
  111.   return err;
  112. }
  113.  
  114. /*
  115. */
  116.  
  117. static char *rule_find(char **lhs_)
  118. {
  119.   char *lhs= *lhs_;
  120.   char *rhs= (char *)0;
  121.  
  122.   rule_t **R= &rules[0];
  123.  
  124.   int done;
  125.  
  126.   for(done=0; R[(int)(unsigned char)(*lhs)] && !done; ++lhs)
  127.   {
  128.     rule_t *r= R[ (int)(unsigned char)(*lhs) ];
  129.  
  130.     if( r->rules && (r->rules)[ (int)(unsigned char)(lhs[1]) ] )
  131.       R= r->rules;
  132.  
  133.     else
  134.     {
  135.       rhs= r->rhs;
  136.       done= 1;
  137.     }
  138.   }
  139.  
  140.   if(rhs)
  141.     *lhs_= lhs;
  142.  
  143.   return rhs;
  144. }
  145.  
  146. /*
  147. */
  148.  
  149. static int strexpand_init(char **table)
  150. {
  151.   int err=0;
  152.   int c, t;
  153.  
  154.   /* initialize the rules[] array */
  155.   for(c=0; c<256; c++)
  156.     rules[c]= (rule_t *)0;
  157.  
  158.   /* add the given rules */
  159.  
  160.   if(table)
  161.   {
  162.     for(t=0; table[t] && (err==0); t+=2)
  163.       err= rule_add(table[t], table[t+1]);
  164.   }
  165.  
  166.   return err;
  167. }
  168.  
  169. /*
  170. */
  171.  
  172. static void strexpand_exit(void)
  173. {
  174.   int c;
  175.  
  176.   for(c=0; c<256; c++)
  177.   {
  178.     if(rules[c])
  179.       rules[c]= rule_dispose(rules[c]);
  180.   }
  181. }
  182.  
  183.  
  184. /****** strexpand/strexpand **************************************************
  185. *
  186. *   NAME
  187. *    strexpand -- Expand macros in a string dynamically
  188. *
  189. *   SYNOPSIS
  190. *    str= strexpand(fmt, tab)
  191. *
  192. *    char *strexpand( char *, char ** );
  193. *
  194. *   FUNCTION
  195. *    This function expands all occurences of tab[n] (n even) in `fmt' to
  196. *    tab[n+1] and returns a dynamically allocated string which has to be
  197. *    disposed via free(str) by the user.
  198. *
  199. *    In other words: given translation table `tab' holds substitution-
  200. *    or translation rules with the source string (or left-hand-side)
  201. *    on even places and the destination string (or right-hand-side) on
  202. *    the odd places.  The translation is performed on given string `fmt'
  203. *    in the following way:
  204. *
  205. *            tab[0] -> tab[1]
  206. *            tab[2] -> tab[3]
  207. *            tab[4] -> tab[5]  ....
  208. *
  209. *    I.e.: all occurences of tab[0] in `fmt' will be replaced by tab[1],
  210. *                tab[2]                              tab[3],
  211. *                tab[4]                              tab[5],
  212. *          etc.
  213. *
  214. *   INPUTS
  215. *    fmt          - The format string holding 0 or more of the macros
  216. *
  217. *    tab          - A table of strings with the source string (on even
  218. *            indices) and the destination string.
  219. *            This table must end with a (char *)0 as the last
  220. *            source string.
  221. *
  222. *   RESULT
  223. *    str          - A dynamically allocated copy of `fmt' with all 
  224. *            occurences of t[n] (n even) replaced by t[n+1].
  225. *
  226. *   EXAMPLE
  227. *
  228. *    char *table[] = { "ab"  , "1234",
  229. *                      "abc" , "xyz",
  230. *                      "ef"  , "foobar",  0,0 };
  231. *
  232. *    compiling the translation table via strexpand_init(table) yields the
  233. *    following graph:
  234. *
  235. *              +---+---+---+---+---+---+
  236. *    rules[] = | a | b | c | d | e | f | ....
  237. *              +---+---+---+---+---+---+
  238. *               /\               /\
  239. *              /                   \
  240. *              +---+---+            +---+---+---+---+---+---+
  241. *              | a | b | ....       | a | b | c | d | e | f | ....
  242. *              +---+---+            +---+---+---+---+---+---+
  243. *                   /\                                    /\
  244. *                  /  \                                     \
  245. *                 /    +-- "1234"                            +-- "foobar"
  246. *                /
  247. *               /
  248. *              +---+---+---+---+---+---+
  249. *              | a | b | c | d | e | f | ....
  250. *              +---+---+---+---+---+---+
  251. *                       /\
  252. *                         \
  253. *                          +-- "xyz"
  254. *
  255. *    strexpand("abcdefgab!",table); returns "xyzdfoobarg1234!".
  256. *
  257. *   SEE ALSO
  258. *
  259. ******************************************************************************
  260. *
  261. *
  262. */
  263.  
  264. char *strexpand(char *fmt, char **tab)
  265. {
  266.   char *buf= (char *)0;
  267.  
  268.   if(fmt && *fmt)
  269.   {
  270.     if( strexpand_init(tab) == 0 )
  271.     {
  272.       size_t len= strlen(fmt) + 1;  /* size of output buffer */
  273.  
  274.       if( (buf= (char *)malloc(len*sizeof(char))) )
  275.       {
  276.         unsigned int pos= 0; /* char position in buf */
  277.  
  278. /**/
  279.         while(buf && *fmt)
  280.         {
  281.           char *rhs= rule_find( &fmt );
  282.  
  283.           if(rhs)
  284.           {
  285.             while(*rhs)
  286.             {
  287.               buf[pos++]= *rhs++;
  288.  
  289.               if(pos >= len)
  290.               {
  291.                 char *old= buf;
  292.  
  293.                 len += 1024;
  294.                 buf= (char *)realloc(buf,len*sizeof(char));
  295.  
  296.                 if(!buf)
  297.                   free(old);
  298.               }
  299.             }
  300.           }
  301.           else /* !rhs */
  302.           {
  303.             buf[pos++]= *fmt++;
  304.  
  305.             if(pos >= len)
  306.             {
  307.               char *old= buf;
  308.  
  309.               len += 1024;
  310.               buf= (char *)realloc(buf,len*sizeof(char) );
  311.  
  312.               if(!buf)
  313.                 free(old);
  314.             }
  315.           }
  316.         }
  317. /**/
  318.         if(buf)
  319.           buf[pos]= '\0';
  320.  
  321. /*printf("strexpand(): pos=%d, len=%d\n",pos,len);*/
  322.       }
  323.     }
  324.     strexpand_exit();
  325.   }
  326.  
  327.   return buf;
  328. }
  329.  
  330.  
  331.  
  332. #ifdef TEST
  333.  
  334. #include <stdio.h>
  335.  
  336. char *table[] = { "ab"  , "1234",
  337.                   "abc" , "xyz",
  338.                   "ef"  , "foobar",  0,0 };
  339.  
  340. int main(int argc, char **argv)
  341. {
  342.   while(--argc > 0)
  343.   {
  344.     char *s= strexpand(*++argv, table);
  345.  
  346.     if(s)
  347.     {
  348.       puts(s);
  349.       free(s);
  350.     }
  351.     else printf("strexpand(\"%s\") failed.\n",*argv);
  352.   }
  353.  
  354.   return 0;
  355. }
  356.  
  357. #endif /*TEST*/
  358.